package com.hmdp.service.impl;

import ch.qos.logback.core.recovery.ResilientFileOutputStream;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.Shop;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *

 */
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 更新数据库后删除缓存
     *
     * @param shop
     * @return
     */
    @Transactional
    public Result updateWithRedis(Shop shop) {
        Long id = shop.getId();
        if (id == null) return Result.fail("店铺id不能为空");

        String key = RedisConstants.CACHE_SHOP_KEY + shop.getId();

        //1.更新数据库
        boolean updated = updateById(shop);
        if (!updated) {
            return Result.fail("更新数据库失败!");
        }
        //2.删除对应缓存
        stringRedisTemplate.delete(key);
        return Result.ok();
    }

    /**
     * 使用redis缓存店铺信息
     *
     * @param id
     * @return
     */
    public Result queryById(Long id) {
        String key = RedisConstants.CACHE_SHOP_KEY + id;
        //查询redis中是否存在该商铺
        String shopJson = stringRedisTemplate.opsForValue().get(key);
        //存在直接返回,但是需要序列化成对象Shop
        if (StrUtil.isNotBlank(shopJson)) {
            Shop shop = JSONUtil.toBean(shopJson, Shop.class);
            return Result.ok(shop);
        }

        //如果shopJson是空数据，说明已经redis缓存过空值了,数据库中不存在该数据，(上面命中后直接返回数据)
        if("".equals(shopJson)){
            return Result.fail("店铺不存在");
        }

        //不存在，先查数据库，如果数据库中存在该店铺则存入缓存，然后返回
        Shop shop = getById(id);

        //如果数据库中也没，则查询失败
        if (shop == null) {
            //如果查不到，则缓存空值，以防缓存穿透(2min)
            stringRedisTemplate.opsForValue().set(key, "", RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);

            return Result.fail("不存在当前店铺");
        }
        //数据库中存在则先存入redis，注意是用string存储json，不是对象Shop
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);

        return Result.ok(shop);
    }


    /**
     * 尝试获取锁
     */
    private boolean tryLock(String key){
        //1.设置互斥锁,redis里的 setnx 是指如果存在就不能再创建,相当于"互斥"
        Boolean res = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
        return BooleanUtil.isTrue(res);
    }

    /**
     * 尝试释放锁
     * @param key
     */
    private void unLock(String key ){
        //即删除key锁
        stringRedisTemplate.delete(key);
        
    }
}
